package com.hxzy.controller.admin;

import com.hxzy.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Api(tags = "Redisson锁测试")
@RequestMapping(value = "/redis")
@RestController
public class RedissonLockController {

    //redisson用的，它的存储数据类型是   hash来存储
    private String key="redis_lock:A";

    //测试更改的值
    private String changeKey="String:value:test";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @ApiOperation(value = "读锁")
    @GetMapping(value = "/read")
    public R  read(){
        Object obj=null;

        RReadWriteLock readWriteLock = this.redissonClient.getReadWriteLock(key);
        RLock readLock = readWriteLock.readLock();

        System.out.println("线程" + Thread.currentThread().getId() + ",进入了read（）准备加锁");

        //上锁
        readLock.lock();
        try {

            System.out.println("线程" + Thread.currentThread().getId() + ",加了读锁");
            Thread.sleep(5000);

//            RLock readlock02=readWriteLock.readLock();
//            readlock02.lock();
//            //做什么事情
//            System.out.println("线程" + Thread.currentThread().getId() + ",在读锁里面再加了,加了读锁");
//            Thread.sleep(15000);
//            readlock02.unlock();
//            System.out.println("线程" + Thread.currentThread().getId() + ",在读锁里面再加了,释放读锁");


            obj = this.redisTemplate.opsForValue().get(changeKey);

            System.out.println("线程" + Thread.currentThread().getId() + ",读取了redis_lock:A的数据:" + obj.toString());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            readLock.unlock();
            System.out.println("线程"+Thread.currentThread().getId()+",释放读锁");
        }


        return R.okHasData(obj);
    }

    @ApiOperation(value = "写锁")
    @PostMapping(value = "/write")
    public R write() throws InterruptedException {

        Object obj=null;

        RReadWriteLock readWriteLock = this.redissonClient.getReadWriteLock(key);
        //定义一个写锁
        RLock writeLock = readWriteLock.writeLock();

        //写锁加锁
        writeLock.lock();

        try{
            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁*****");

             Thread.sleep(15000);

            this.redisTemplate.opsForValue().increment(changeKey);

            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁，更新数据成功*****");

            //读取数据
            obj=this.redisTemplate.opsForValue().get(changeKey);
            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁，读取数据值为*****,"+obj.toString());
        }finally {
            writeLock.unlock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",释放写锁*****");
        }

        return R.okHasData(obj);
    }

    @ApiOperation(value = "写锁里面再加写锁")
    @PostMapping(value = "/write02")
    public R write2() throws InterruptedException {

        Object obj=null;

        RReadWriteLock readWriteLock = this.redissonClient.getReadWriteLock(key);
        //定义一个写锁
        RLock writeLock = readWriteLock.writeLock();

        //写锁加锁
        writeLock.lock();

        try{
            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁*****");

            Thread.sleep(3000);

            RLock writeLock02 = readWriteLock.writeLock();
            writeLock02.lock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",写锁里面，再加写锁*****");

            System.out.println("----在第二个写锁里面做事情-------");

            writeLock02.unlock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",写锁里面，释放写锁成功*****");


            this.redisTemplate.opsForValue().increment(changeKey);

            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁，更新数据成功*****");

            //读取数据
            obj=this.redisTemplate.opsForValue().get(changeKey);
            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁，读取数据值为*****,"+obj.toString());
        }finally {
            writeLock.unlock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",释放写锁*****");
        }

        return R.okHasData(obj);
    }


    @ApiOperation(value = "读锁里面再写锁不可能的")
    @PostMapping(value = "/read_write")
    public R read_write() throws InterruptedException {

        Object obj=null;

        RReadWriteLock readWriteLock = this.redissonClient.getReadWriteLock(key);
        //定义一个读锁
        RLock readLock = readWriteLock.readLock();

        //写锁加锁
        readLock.lock();

        try{
            System.out.println("**********线程"+Thread.currentThread().getId()+",加了读锁*****");

            Thread.sleep(3000);

            RLock writeLock02 = readWriteLock.writeLock();
            writeLock02.lock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",读锁里面，再加写锁*****");

            System.out.println("----在第二个读锁里面做事情-------");

            writeLock02.unlock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",写锁里面，释放写锁成功*****");


            this.redisTemplate.opsForValue().increment(changeKey);

            System.out.println("**********线程"+Thread.currentThread().getId()+",加了读锁，更新数据成功*****");

            //读取数据
            obj=this.redisTemplate.opsForValue().get(changeKey);
            System.out.println("**********线程"+Thread.currentThread().getId()+",加了读锁，读取数据值为*****,"+obj.toString());
        }finally {
            readLock.unlock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",释放读锁*****");
        }

        return R.okHasData(obj);
    }


    @ApiOperation(value = "写锁里面再读锁可重入")
    @PostMapping(value = "/write_read")
    public R write_read() throws InterruptedException {

        Object obj=null;

        RReadWriteLock readWriteLock = this.redissonClient.getReadWriteLock(key);
        //定义一个读锁
        RLock writeLock = readWriteLock.writeLock();

        //写锁加锁
        writeLock.lock();

        try{
            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁*****");

            Thread.sleep(3000);

            RLock readLock = readWriteLock.readLock();
            readLock.lock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",写锁里面，再加读锁*****");

            System.out.println("----在第二个写锁里面做事情-------");

            readLock.unlock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",写锁里面，释放读锁成功*****");


            this.redisTemplate.opsForValue().increment(changeKey);

            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁，更新数据成功*****");

            //读取数据
            obj=this.redisTemplate.opsForValue().get(changeKey);
            System.out.println("**********线程"+Thread.currentThread().getId()+",加了写锁，读取数据值为*****,"+obj.toString());
        }finally {
            writeLock.unlock();
            System.out.println("**********线程"+Thread.currentThread().getId()+",释放写锁*****");
        }

        return R.okHasData(obj);
    }
}
